#include "Gladiator.h"
#include "GladiatorOwnedStates.h"
#include "Inventory.h"
#include "EntityNames.h"

#include <ctime>
#include <iostream>
#include <iomanip>
using namespace std;


//Initialize Gladiator Object
//---------------------------------------------
Gladiator::Gladiator(int id):BaseGameEntity(id)
{
	level = 1;
	MaxHP = 100;
	CurrentHP = MaxHP;
	EXP = 0;
	Attack = 50;
	MaxDefense = 40;
	CurrentDefense = MaxDefense;
	Money = 100;

	m_Location = WestGate;
	
	m_pCurrentState = InitialState::Instance();
}

//Update Gladiator State
//-------------------------------------------------
int Gladiator::Update()
{

	if(m_pCurrentState)
	{
		m_pCurrentState->Execute(this);
	}

	return m_Location;
}

//Change State
//---------------------------------------------
void Gladiator::ChangeState(State* pNewState)
{
	//make sure both states are valid before attempting to call their methods
	assert(m_pCurrentState && pNewState);

	//call the exit method of the current state
	m_pCurrentState->Exit(this);

	//change the state to the new state
	m_pCurrentState = pNewState;

	//call the entry method of the new state
	m_pCurrentState->Enter(this);
}

//manually set stats for gladiator
void Gladiator::setData(int lvl, int mxhp, int xp, int a, int md, int cd, int m)
{
	if(lvl <= MAX_LEVEL)
		level = lvl;
	else
		level = MAX_LEVEL;
	if(MaxHP <= MAX_HP)
		MaxHP = mxhp;
	else
		MaxHP = MAX_HP;
	CurrentHP = MaxHP;
	EXP = xp;
	Attack = a;
	MaxDefense = md;
	CurrentDefense = cd;
	Money = m;
}

//display Gladiator's Stats
void Gladiator::displayStatus()
{
	cout << "CURRENT STATS" << endl;
	cout << "--------------------------------" << endl;
	cout << setw(15) << left << "Level:" << " " << setw(10) << right << level << endl;
	cout << setw(15) << left << "HP:" << " " << setw(6) << right << CurrentHP << "/" << MaxHP << endl;
	cout << setw(15) << left << "EXP:" << " " << setw(10) << right << EXP << endl;
	cout << setw(15) << left << "Attack:" << " " << setw(10) << right << Attack << endl;
	cout << setw(15) << left << "Defense:" << " " << setw(10) << right << CurrentDefense << endl;
	cout << setw(15) << left << "Money:" << " " << setw(10) << right << Money << endl;
}


//Load and Set Save Data from file
//-----------------------------------------------
bool Gladiator::loadSaveData()
{
	ifstream savefile;
	int lvl, mxhp, xp, a, md, cd, m;
	int i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14;
	int eqweap, eqarm;
	//open file
	savefile.open("savedata.txt");
	if(!savefile)
	{
		return false;
	}
	else
	{
		savefile >> lvl;
		savefile >> mxhp;
		//when loading a game, start player off with full HP
		//CurrentHP = MaxHP;
		savefile >> xp;
		savefile >> a;
		savefile >> md;
		savefile >> cd;
		savefile >> m;

		setData(lvl, mxhp, xp, a, md, cd, m);

		//determine way to load inventory

		savefile >> i1;
		savefile >> i2;
		savefile >> i3;
		savefile >> i4;
		savefile >> i5;
		savefile >> i6;
		savefile >> i7;
		savefile >> i8;
		savefile >> i9;
		savefile >> i10;
		savefile >> i11;
		savefile >> i12;
		savefile >> i13;
		savefile >> i14;

		pack.setInv(i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14);

		savefile >> eqweap;
		pack.setEquipWeap(eqweap);
		savefile >> eqarm;
		pack.setEquipArm(eqarm);
		
		return true;
	}
}

//Save Data to file
//------------------------------------------------------------
void Gladiator::SaveData()
{
	ofstream savefile;
	savefile.open("savedata.txt");

	savefile << level << " " << MaxHP << " " << EXP << " " << Attack << 
		" " << MaxDefense << " " << CurrentDefense << " " << Money << " ";
	//determine a way to save inventory
	for(int i = 0; i < pack.getSize(); i++)
	{
		savefile << pack.getInv(i) << " ";
	}

	savefile << pack.getEquipWeap() << " " << pack.getEquipArm();

	savefile << endl;
}

//update money after purchasing items from the inventory class
bool Gladiator::purchase(int x)
{
	if((Money - x) >= 0)
	{
		Money -= x;
		return true;
	}
	else
		return false;
}

//restores hp while sleeping
void Gladiator::sleep()
{
	CurrentHP = MaxHP;
}

//increases gladiators health by designated amount
void Gladiator::healthBoost(int hp)
{
	//make sure hp boost does not exceed max
	if((CurrentHP + hp) <= MaxHP)
		CurrentHP += hp;
	else
		CurrentHP = MaxHP;
}

//called each round of combat to check current defense
//if current defense is over max (hang over from tavern)
//decrement bonus defense once until current defense is 
//back to max
void Gladiator::defenseCheck()
{
	if(CurrentDefense > MaxDefense)
		CurrentDefense--;
}

//if gladiator drinks enough beers, he'll recieve a
//temporary defense boost
void Gladiator::hangover(int x)
{
	CurrentDefense += x;
}

//make sure players don't stack defense boosts
bool Gladiator::gotDefBoost()
{
	if(CurrentDefense > MaxDefense)
		return true;
	else
		return false;
}

//increase attack after equipping weapon
void Gladiator::weaponBoost(int a)
{
	Attack += a;
}

//increase defense after equipping armor
void Gladiator::armorBoost(int d)
{
	MaxDefense += d;
	CurrentDefense += d;
}

//decrease attack after removing weapon
void Gladiator::removeWeapon(int a)
{
	Attack -= a;
}

//increase defense after removing armor
void Gladiator::removeArmor(int d)
{
	MaxDefense -= d;
	CurrentDefense -= d;
}

//increase money after selling items
void Gladiator::sell(int m)
{
	Money += m;
}

//determines how much damage is recieved from attack
//returns true if gladiator has been killed
bool Gladiator::ReceiveDamage(int x)
{
	int damage;

	//calculate damage
	if(x <= CurrentDefense)
	{
		damage = rand()%5;
	}
	else
	{
		damage = (x - CurrentDefense) + rand()%5;
	}
	//calculate hp after damage deduction
	CurrentHP -= damage;

	cout << "\n" << setw(5) << left << " " << GetNameOfEntity(ent_Glad) << " has taken " << damage << " points of damage" << endl;

	//check to see if gladiator is still alive
	if(CurrentHP > 0)
	{
		return false;
	}
	else if (CurrentHP <= 0)
	{
		DeathCry();
		//make sure hp is not negative
		CurrentHP = 0;
		return true;
	}
}

//returns attack damage to deal
int Gladiator::AttackDamage()
{
		Taunt();
		//do normal attack
		return Attack;	
}

//create taunt
void Gladiator::Taunt()
{
	//random number
	int random = rand()%4;
	
	if(random == 0)
	{
		cout << "\n" << GetNameOfEntity(ent_Glad) << ": Take this!" << endl;
	}
	else if (random == 1)
	{
		cout << "\n" << GetNameOfEntity(ent_Glad) << ": Want some more?" << endl;
	}
	else if (random == 2)
	{
		cout << "\n" << GetNameOfEntity(ent_Glad) << ": Try this on for size!" << endl;
	}
	else if (random == 3)
	{
		cout << "\n" << GetNameOfEntity(ent_Glad) << ": Oh yeah!" << endl;
	}
}

//create death cry
void Gladiator::DeathCry()
{
	cout << "\n" << GetNameOfEntity(ent_Glad) << ": Is this really the end?" << endl;
}

//determines how much damage is recieved from attack
//when defending
//returns true if gladiator has been killed
bool Gladiator::OnDefend(int x)
{
	int damage;

	//calculate damage
	//on defend gives a greater defense
	if(x <= (2*CurrentDefense))
	{
		damage = rand()%5;
	}
	else
	{
		damage = (x - (2*CurrentDefense)) + rand()%5;
	}
	//calculate hp after damage deduction
	CurrentHP -= damage;

	cout << "\n" << setw(5) << left << " " << GetNameOfEntity(ent_Glad) << " has taken " << damage << " points of damage" << endl;

	//check to see if gladiator is still alive
	if(CurrentHP > 0)
	{
		return false;
	}
	else if (CurrentHP <= 0)
	{
		DeathCry();
		//make sure hp is not negative
		CurrentHP = 0;
		return true;
	}
}

//prints hp
void Gladiator::printHP()
{
	cout << CurrentHP << "/" << MaxHP;
}

//victory function to add xp and and money
void Gladiator::victory(int xp, int m)
{
	EXP += xp;
	Money += m;

	if(levelUp())
	{
		cout << setw(8) << left << " " << "LEVEL UP!!!\n" << endl;
	}

	cout << "+ " << xp << " EXP" << endl;
	cout << "+ " << m << "g" << endl;
}

//Level Up Gladiator Stats
bool Gladiator::levelUp()
{
	switch(level)
	{
	case 1:
		//level 1
		if(EXP >= 100)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 2:
		//level 2
		if(EXP >= 250)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 3:
		//level 3
		if(EXP >= 500)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 4:
		//level 4
		if(EXP >= 1000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 5:
		//level 5
		if(EXP >= 1700)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 6:
		//level 6
		if(EXP >= 2500)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 7:
		//level 7
		if(EXP >= 3500)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 8:
		//level 8
		if(EXP >= 5000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 9:
		//level 9
		if(EXP >= 6700)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 10:
		//level 10
		if(EXP >= 8300)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 11:
		//level 11
		if(EXP >= 10000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 12:
		//level 12
		if(EXP >= 12200)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 13:
		//level 13
		if(EXP >= 15000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 14:
		//level 14
		if(EXP >= 19500)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 15:
		//level 15
		if(EXP >= 25000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 16:
		//level 16
		if(EXP >= 32000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 17:
		//level 17
		if(EXP >= 40000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 18:
		//level 18
		if(EXP >= 50000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 19:
		//level 19
		if(EXP >= 65000)
		{
			level++;
			Attack += 5;
			CurrentDefense += 5;
			MaxDefense += 5;
			CurrentHP += 10;
			MaxHP += 10;
			return true;
		}
		else
			return false;
		break;
	case 20:
		//level 20
		//max level
		return false;
		break;
	default:
		cout << "\n\nERROR\n\n" << endl;
		return false;
		break;
	}
}